Skip to content

[1/5] Aitools: state tracking, manifest source, directory rename#4810

Merged
simonfaltum merged 7 commits intomainfrom
simonfaltum/aitools-pr1-state
Mar 25, 2026
Merged

[1/5] Aitools: state tracking, manifest source, directory rename#4810
simonfaltum merged 7 commits intomainfrom
simonfaltum/aitools-pr1-state

Conversation

@simonfaltum
Copy link
Copy Markdown
Member

@simonfaltum simonfaltum commented Mar 22, 2026

PR Stack

This is part of the aitools feature-complete initiative. PRs should be reviewed and merged in order.

  1. [1/5] State + release discovery + directory rename (this PR)
  2. [2/5] Install writes state + interactive agent selection ([2/5] Aitools: install writes state, interactive agent selection, idempotent install #4811)
  3. [3/5] Update + uninstall + version commands ([3/5] Aitools: update, uninstall, and version commands #4812)
  4. [4/5] List improvements + command restructuring + flags ([4/5] Aitools: list command, flat structure, --skills/--agents/--include-experimental flags #4813)
  5. [5/5] Project scope (--project/--global) (pending)

Manifest v2 PR: (pending in databricks-agent-skills)

Why

The aitools skills installer has no state tracking. There's no record of what was installed, at what version, or when. This blocks every lifecycle command (update, uninstall, version). The manifest fetching logic is also hardcoded with no abstraction for testing.

Changes

Before: Skills install to ~/.databricks/agent-skills/ with no state file. FetchManifest is inlined in installer.go with a hardcoded ref and no way to mock it in tests.

Now:

  • InstallState type with LoadState/SaveState (atomic write via temp+rename) for tracking installed skills, release ref, and timestamps
  • ManifestSource interface with GitHubManifestSource, separating manifest fetching from install logic. Enables test mocking.
  • FetchLatestRelease to discover newest release from GitHub API. Falls back to pinned ref on network failure.
  • v2 fields on SkillMeta (Experimental, Description, MinCLIVer) with omitempty for backward compat with v1 manifests
  • Canonical directory renamed from .databricks/agent-skills to .databricks/aitools/skills
  • Backward-compat check in HasDatabricksSkillsInstalled for the old path

No behavior changes to existing commands except the directory path.

Test plan

  • LoadState returns nil, nil for nonexistent file
  • SaveState + LoadState roundtrip preserves all fields including optional ones
  • SaveState creates nested directories, writes trailing newline
  • LoadState returns error for corrupt JSON
  • GlobalSkillsDir resolves correctly
  • ProjectSkillsDir returns ErrNotImplemented
  • HasDatabricksSkillsInstalled detects legacy path
  • All existing aitools tests still pass

…tory

Add state types (InstallState) with atomic load/save persistence, path
resolution (GlobalSkillsDir, ProjectSkillsDir stub), ManifestSource
interface with GitHub implementation, latest release discovery
(FetchLatestRelease), and Clock abstraction. Extend SkillMeta with v2
fields (Experimental, Description, MinCLIVer). Refactor FetchManifest
to delegate to GitHubManifestSource. Rename canonical skills directory
from .databricks/agent-skills to .databricks/aitools/skills with
backward-compat check for the old path.

Co-authored-by: Isaac
- Rename SkillsRef->Release, LastChecked->LastUpdated (time.Time), simplify
  Skills to map[string]string, add IncludeExperimental and Scope fields.
- Remove unused Clock/RealClock from source.go.
- Add trailing newline to SaveState JSON output.
- Improve FetchLatestRelease doc comment on error/fallback contract.
- Document intentional DATABRICKS_SKILLS_REF duplication.

Co-authored-by: Isaac
@github-actions
Copy link
Copy Markdown

Suggested reviewers

Based on git history of the changed files, these people are best suited to review:

  • @arsenyinfo -- recent work in experimental/aitools/lib/installer/, experimental/aitools/lib/agents/
  • @pietern -- recent work in experimental/aitools/lib/installer/, experimental/aitools/lib/agents/

Confidence: high

Eligible reviewers

Based on CODEOWNERS, these people or teams could also review:

@databricks/eng-apps-devex, @lennartkats-db

Suggestions based on git history of 6 changed files (3 scored). See CODEOWNERS for path-specific ownership rules.

Copy link
Copy Markdown
Contributor

@arsenyinfo arsenyinfo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my understanding, after these changes we're always pulling latest skills rather than pinned version - is it intentional?

Other than that, given the new canonical path, I'd advocate for migration mechanism when installer is triggered

@simonfaltum
Copy link
Copy Markdown
Member Author

re Migration: I don't think we should be adding migration for the directory rename. This is an experimental feature with a small number of users who opted in. HasDatabricksSkillsInstalled() already detects both old and new paths, so we can surface a "please reinstall" message when we detect the old path. I don't think we really need a migration at this stage

Skills version is pinned at CLI build time via defaultSkillsRepoRef.
No need to call the GitHub releases API for version discovery.

Co-authored-by: Isaac
@simonfaltum simonfaltum enabled auto-merge March 24, 2026 13:44
@simonfaltum simonfaltum added this pull request to the merge queue Mar 25, 2026
Merged via the queue into main with commit ead07cf Mar 25, 2026
15 checks passed
@simonfaltum simonfaltum deleted the simonfaltum/aitools-pr1-state branch March 25, 2026 22:10
@eng-dev-ecosystem-bot
Copy link
Copy Markdown
Collaborator

Commit: ead07cf

Run: 23566746901

github-merge-queue bot pushed a commit that referenced this pull request Mar 25, 2026
…mpotent install (#4811)

## PR Stack

1. [1/5] State + release discovery + directory rename (#4810)
2. **[2/5] Install writes state + interactive agent selection** (this
PR)
3. [3/5] Update + uninstall + version commands (#4812)
4. [4/5] List improvements + command restructuring + flags (#4813)
5. [5/5] Project scope (--project/--global) (pending)

**Base**: `simonfaltum/aitools-pr1-state` (PR 1)

## Why

Install currently has no state tracking, no filtering, and outputs every
file download to the console. Users can't tell what version they have,
and there's no way to install for specific agents.

## Changes

Before: `skills install` downloads everything, prints every file, has no
state, no filtering, no agent selection.

Now:
- `InstallSkillsForAgents(ctx, src, agents, opts)` as the core install
function. `InstallAllSkills` becomes a thin wrapper (signature preserved
for `cmd/apps/init.go` compat).
- State written to `.state.json` after successful install. Merges with
existing state (doesn't overwrite).
- Idempotent: second install skips already-present skills with matching
versions.
- Experimental filtering: skip `experimental: true` skills by default.
- `min_cli_version` enforcement: skip incompatible skills with warning
(hard error for single-skill install).
- Interactive agent selection via `charmbracelet/huh` multi-select. Skip
prompt for 1 agent, all detected for non-interactive.
- Legacy install detection: prints "reinstall" message when old install
found without state.
- Concise default output (2 lines). Per-file detail only at debug level.

## Test plan

- [x] State created after install-all and install-single
- [x] Experimental filtering (skip by default, include with flag)
- [x] min_cli_version: warning for all, hard error for single
- [x] Idempotent: skip same version, update changed
- [x] Legacy detection with helpful message
- [x] Interactive prompt for 2+ agents, skip for 1
- [x] Non-interactive: all detected, no prompt
- [x] `InstallAllSkills` signature preserved
- [x] Concise output, per-file at debug level
github-merge-queue bot pushed a commit that referenced this pull request Mar 25, 2026
## PR Stack

1. [1/5] State + release discovery + directory rename (#4810)
2. [2/5] Install writes state + interactive agent selection (#4811)
3. **[3/5] Update + uninstall + version commands** (this PR)
4. [4/5] List improvements + command restructuring + flags (#4813)
5. [5/5] Project scope (--project/--global) (pending)

**Base**: `simonfaltum/aitools-pr2-install` (PR 2)

## Why

Users can install skills but can't update, uninstall, or check what
version they have. These are core lifecycle gaps.

## Changes

Three new commands, each small but grouped because they share patterns.

**`aitools update`**: Compares installed release against latest.
Downloads changed skills. Flags: `--check` (dry run), `--force`
(re-download), `--no-new` (don't auto-add new manifest skills).
Authoritative release detection (distinguishes real API response from
fallback). Applies experimental and min_cli_version filtering. Warns on
skills removed from manifest.

**`aitools uninstall`**: Removes skill directories from canonical
location. Removes symlinks from ALL agent directories (full registry
scan, not just detected). Cleans orphaned symlinks. Only removes
symlinks pointing to canonical dir (safe for third-party skills).
Deletes `.state.json` on success.

**`aitools version`**: Shows installed version, skill count, last
updated date. Best-effort staleness check against latest release.
Graceful offline degradation. Suppresses staleness check when
`DATABRICKS_SKILLS_REF` is set.

## Test plan

- [x] Update: no state -> error, already up to date, version diff, check
dry run, force, no-new, new skill auto-installed, removed skill warning
- [x] Uninstall: removes dirs + symlinks, orphan cleanup, state
deletion, no state -> error, missing dirs handled
- [x] Version: installed/up-to-date, update available, not installed,
offline graceful
- [x] All lint checks pass
github-merge-queue bot pushed a commit that referenced this pull request Mar 26, 2026
…ude-experimental flags (#4813)

## PR Stack

1. [1/5] State + release discovery + directory rename (#4810)
2. [2/5] Install writes state + interactive agent selection (#4811)
3. [3/5] Update + uninstall + version commands (#4812)
4. **[4/5] List improvements + command restructuring + flags** (this PR)
5. [5/5] Project scope (--project/--global) (#4814)

Manifest v2 PR: databricks/databricks-agent-skills#35

**Base**: `simonfaltum/aitools-pr3-lifecycle` (PR 3)

## Why

Commands are nested under `skills` which burns namespace for future
component types (hooks, etc.). There's no way to install specific
skills, target specific agents from the CLI, or see installed status in
the list output.

## Changes

**New `list` command**: Table output with skill names, versions,
installed status, `[experimental]` tags. Sorted alphabetically. Uses
`tabwriter` for alignment.

**Flat command structure**: `aitools
install/update/uninstall/list/version` at the top level. Hidden `skills
install` and `skills list` aliases for backward compat.

**Flags**:
- `--skills` (string, comma-separated) on install, update, uninstall:
operate on specific skills
- `--skills` (bool) on list, version: show detailed skills view
- `--agents` (string, comma-separated) on install: target specific
agents, validates against registry, skips interactive prompt
- `--include-experimental` on install: include experimental skills

**Selective uninstall**: `--skills` on uninstall removes only named
skills, preserves state file with remaining.

## Test plan

- [x] `install --skills`, `--agents`, `--include-experimental` flags
work
- [x] `--agents` validates against registry, errors on unknown
- [x] `uninstall --skills` selective removal, state preserved
- [x] `update --skills` selective update
- [x] `list` shows detailed table
- [x] `skills install` and `skills list` hidden aliases work (Execute
path tested)
- [x] `cmd/apps/init.go` integration preserved
- [x] All lint checks pass
github-merge-queue bot pushed a commit that referenced this pull request Mar 26, 2026
## PR Stack

1. [1/5] State + release discovery + directory rename (#4810)
2. [2/5] Install writes state + interactive agent selection (#4811)
3. [3/5] Update + uninstall + version commands (#4812)
4. [4/5] List improvements + command restructuring + flags (#4813)
5. **[5/5] Project scope (--project/--global)** (this PR)

Manifest v2 PR: databricks/databricks-agent-skills#35

**Base**: `simonfaltum/aitools-pr4-restructure` (PR 4)

## Why

Skills are currently global-only. Teams working on the same project
can't share a curated set of skills via their repo. Project-scoped
installation puts skills alongside the code, so they can be committed to
git and shared.

## Changes

Before: All skills install to `~/.databricks/aitools/skills/` (global
only).

Now:
- `--project` flag on install, update, uninstall: operates on
`<cwd>/.databricks/aitools/skills/`
- `--global` flag: explicit global scope (default behavior)
- `--global` + `--project` -> error
- Interactive scope prompt on install (default: global). Uses
`huh.NewSelect` in cmd layer.
- Non-interactive defaults to global.
- `SupportsProjectScope` field on `Agent` struct. Only Claude Code and
Cursor support project scope.
- Incompatible agents get a warning, not an error: "Skipped <agent>:
does not support project-scoped skills."
- Version shows both scopes when both exist.
- State includes `scope: "project"` field for project installs.

## Test plan

- [x] `--project` installs to cwd-relative directory
- [x] `--global` + `--project` -> error
- [x] No flag, interactive -> scope prompt shown, default is global
- [x] No flag, non-interactive -> global (no prompt)
- [x] Incompatible agents warned, not errored
- [x] Symlinks only created for capable agents in project scope
- [x] Version shows both scopes when both exist
- [x] `SupportsProjectScope` set correctly for all 6 agents
- [x] All lint checks pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants